上一篇說到用 significant text aggregation 補完沒有打完的字;那補完這個字了,下一步是要找出這個字的延伸字,也就是如果是 covid,那 covid 後面應該會接什麼呢?這個思考方向蠻單純的,就是找跟 covid 這個詞最相關的,那在 es 要怎麼做呢?
看標題應該有猜到,又是 significant text!不過這次把 include 改成 exclude :
GET /covid19_tweets/_search
{
  "query": {
    "match": {
      "tweet": "covid"
    }
  },
  "aggs": {
    "tags": {
      "significant_text": {
        "field": "tweet",
        "**exclude**": "covid",
        "size": 3,
        "min_doc_count": 100
      }
    }
  }
}
exclude 就是找出的 token 不要包含某個或某些 token 的設定,在這邊是希望把搜尋詞本身(covid)去掉,也就是建議的接續詞內不應包含搜尋詞本身。
這次得到的結果蠻不理想的:
{
  "took": 801,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": 2.9927912,
    "hits": [
      ... (略) ...
    ]
  },
  "aggregations": {
    "tags": {
      "doc_count": 32250,
      "bg_count": 354600,
      "buckets": [
        {
          "key": "19",
          "doc_count": 26206,
          "score": 3.579179955827552,
          "bg_count": 53314
        },
        {
          "key": "https",
          "doc_count": 19696,
          "score": 0.10720518675055014,
          "bg_count": 184226
        },
        {
          "key": "t.co",
          "doc_count": 19696,
          "score": 0.10703375846470577,
          "bg_count": 184270
        }
      ]
    }
  }
}
得到了 19 、 https 、 t.co  這樣的結果,其中除了 19 是合理外, https 和 t.co 感覺對使用者不太有幫助;主要是因為 tweeter 的內容除了文字之外,也存在很多網站連結,並且在我們的 index setting 中沒有指定 analyzer,ES 使用了預設的 standard analyzer,這個 analyzer 會將 url 文字部分切取成 token,因此只要有連結的 tweet 就會存在 https。
我們在 index setting 中嘗試定義自己的 analyzer ,看是不是可以讓結果變的理想一點:
{"analysis": {
      "analyzer": {
        "index_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase"
          ],
          "char_filter": [
            "pun_filter"
          ]
        }
      }, 
      "char_filter": {
        "pun_filter": {
              "type": "mapping",
              "mappings": [
                "/=> ",
                ".=>",
                "ー=>"
              ]
            }
      }
    }}
修改 mappings 於 tweet field 使用 settings 中的 index_analyzer:
{
"properties": {
...(略)...
**"tweet": {"type": "text", "analyzer": "index_analyzer"},**
...(略)...
}
刪除原本的 index,修改寫入資料的 python script 如下後再執行一次:
...(略)...
index_mapping_file = 'index_mapping.json'
**index_setting_file = 'index_settings.json' # 新增這行**
...(略)...
# read index mapping file
with open(index_mapping_file, 'r') as f:
    index_mapping = json.load(f)
**# read index setting file                  # 新增這段
with open(index_setting_file, 'r') as f:
    index_setting = json.load(f)**
...(略)...
# create index
**r = es_cli.indices.create(index=index_name, mappings=index_mapping, settings=index_setting) # 修改這一行**
...(略)...
得到了這樣的結果:
{
  "took": 510,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": 3.009927,
    "hits": [
      ...(略)...
    ]
  },
  "aggregations": {
    "tags": {
      "doc_count": 15739,
      "bg_count": 88210,
      "buckets": [
        {
          **"key": "19",**
          "doc_count": 12673,
          "score": 3.624382620593038,
          "bg_count": 12911
        },
        {
          **"key": "the",**
          "doc_count": 8164,
          "score": 0.10506112232239737,
          "bg_count": 38049
        },
        {
          **"key": "pandemic",**
          "doc_count": 1026,
          "score": 0.09701440718573524,
          "bg_count": 2311
        }
      ]
    }
  }
}
看起來比較合理了,但是還是有一些可以優化的地方:
the 應該算是個停頓詞,出現在 suggestion 不太適合(或說沒什麼用)下一篇來試試看組合起來這兩個部分的效果吧~